﻿#include "converter.h"

#include <Windows.h>
#include <codecvt>

namespace util {
// std::string 转换为 UTF-8 编码
std::string string_to_utf8(const std::string& str) {
    int nwLen = ::MultiByteToWideChar(CP_ACP, 0, str.c_str(), -1, NULL, 0);

    wchar_t* pwBuf = new wchar_t[nwLen + 1];   // 一定要加1，不然会出现尾巴
    ZeroMemory(pwBuf, nwLen * 2 + 2);

    ::MultiByteToWideChar(CP_ACP, 0, str.c_str(), (int)str.length(), pwBuf, nwLen);

    int nLen = ::WideCharToMultiByte(CP_UTF8, 0, pwBuf, -1, NULL, NULL, NULL, NULL);

    char* pBuf = new char[nLen + 1];
    ZeroMemory(pBuf, nLen + 1);

    ::WideCharToMultiByte(CP_UTF8, 0, pwBuf, nwLen, pBuf, nLen, NULL, NULL);

    std::string retStr(pBuf);

    delete[] pwBuf;
    delete[] pBuf;

    return retStr;
}

bool gzip_comp(const std::string& input, std::string& output, int params) {
    boost::iostreams::filtering_ostream fos;
    fos.push(boost::iostreams::gzip_compressor(boost::iostreams::gzip_params(params)));
    fos.push(boost::iostreams::back_inserter(output));
    fos << input;
    boost::iostreams::close(fos);

    return true;
}

bool gzip_decomp(const std::string& input, std::string& output) {
    boost::iostreams::filtering_ostream fos;
    fos.push(boost::iostreams::gzip_decompressor());
    fos.push(boost::iostreams::back_inserter(output));
    fos << input;   // 把压缩数据按容器长度写入流
    fos << std::flush;
    boost::iostreams::close(fos);

    return true;
}

// 编码
bool Base64Encode(const std::string& input, std::string& output) {
    std::size_t len = input.size();
    output.resize(boost::beast::detail::base64::encoded_size(len));
    output.resize(boost::beast::detail::base64::encode(&output[0], input.c_str(), len));

    return true;
}

// 解码
bool Base64Decode(const std::string& input, std::string& output) {
    std::size_t len = input.size();
    output.resize(boost::beast::detail::base64::decoded_size(len));
    auto result = boost::beast::detail::base64::decode(&output[0], input.data(), len);
    output.resize(result.first);

    return true;
}

std::string UnicodeToUTF8(const std::wstring& wstr) {
    std::string ret;
    try {
        std::wstring_convert<std::codecvt_utf8<wchar_t>> wcv;
        ret = wcv.to_bytes(wstr);
    } catch (const std::exception& e) {
        std::cerr << e.what() << std::endl;
    }
    return ret;
}

std::wstring UTF8ToUnicode(const std::string& str) {
    std::wstring ret;
    try {
        std::wstring_convert<std::codecvt_utf8<wchar_t>> wcv;
        ret = wcv.from_bytes(str);
    } catch (const std::exception& e) {
        std::cerr << e.what() << std::endl;
    }
    return ret;
}

std::string u8str_to_str(const std::u8string& u8str) {
    return std::string(u8str.begin(), u8str.end());
}

std::string utf8_to_gb2312(const std::string& utf8) {
    auto utf8_data = utf8.c_str();

    int      len  = MultiByteToWideChar(CP_UTF8, 0, utf8_data, -1, NULL, 0);
    wchar_t* wstr = new wchar_t[len + 1];
    memset(wstr, 0, len + 1);
    MultiByteToWideChar(CP_UTF8, 0, utf8_data, -1, wstr, len);
    len       = WideCharToMultiByte(CP_ACP, 0, wstr, -1, NULL, 0, NULL, NULL);
    char* str = new char[len + 1];
    memset(str, 0, len + 1);
    WideCharToMultiByte(CP_ACP, 0, wstr, -1, str, len, NULL, NULL);
    if (wstr)
        delete[] wstr;

    return std::string(str);
}

std::string gb2312_to_utf8(const std::string& gb2312) {
    auto gb2312_data = gb2312.c_str();

    int      len  = MultiByteToWideChar(CP_ACP, 0, gb2312_data, -1, NULL, 0);
    wchar_t* wstr = new wchar_t[len + 1];
    memset(wstr, 0, len + 1);
    MultiByteToWideChar(CP_ACP, 0, gb2312_data, -1, wstr, len);
    len       = WideCharToMultiByte(CP_UTF8, 0, wstr, -1, NULL, 0, NULL, NULL);
    char* str = new char[len + 1];
    memset(str, 0, len + 1);
    WideCharToMultiByte(CP_UTF8, 0, wstr, -1, str, len, NULL, NULL);
    if (wstr)
        delete[] wstr;

    return std::string(str);
}

std::string to_local_path(const std::string& path) {
#ifdef WIN32
    // Win32 环境，中文文件名转为 GB2312
    return util::utf8_to_gb2312(path);
#else
    return filename;
#endif
}
}   // namespace util